#-*- coding: utf-8 -*-
from dimg import * #bourrin m'enfin
from copy import deepcopy
from math import radians, sin, cos



"""
TP 7 - Traitement d'images
Par Guillaume HUYSMANS et Mathieu LECLERQ, 2013.

Cet outil est capable d'appliquer différents filtres à une image au format JPEG.
Il fonctionne en ligne de commande et peut donc être utilisé depuis un batch ou un autre logiciel.
[Je doute que ça arrive un jour vu sa lenteur "naturelle", m'enfin on ne sait jamais.]
"""



def shellExecute(f):
	"""
	Ouvre un fichier dont le nom est passé en paramètre.
	Testé sous Windows et Ubuntu (testé)...
	Pris depuis http://stackoverflow.com/a/435669
	"""
	import subprocess, os, sys
	if sys.platform.startswith('darwin'):
		subprocess.call(('open', f))
	elif os.name == 'nt':
		os.startfile(f)
	elif os.name == 'posix':
		subprocess.call(('xdg-open', f))

def greyscale(img):
	"""Convertit l'image en nuances de gris."""
	cp = deepcopy(img)
	for y in range(len(cp)):
		for x in range(len(cp[0])):
			pix = cp[y][x]
			nivgris = int(0.2125*pix[0] + 0.7154*pix[1] + 0.0721*pix[2])
			cp[y][x] = (nivgris, nivgris, nivgris)
	return cp

def invert(img):
	"""Retourne un "négatif" de l'image."""
	cp = deepcopy(img)
	for y in range(len(cp)):
		for x in range(len(cp[0])):
			pix = cp[y][x]
			cp[y][x] = (255-pix[0], 255-pix[1], 255-pix[2])
	return cp

def convo(img, mat):
	"""Applique une matrice de convolution à toute l'image."""
	#On ajoute un bord noir partout. Cette matrice sera celle à partir
	#de laquelle on fera les calculs avec la matrice de convolution mat.
	orig = deepcopy(img)
	for i in range(len(orig)):
		orig[i] = [(0, 0, 0)] + orig[i] + [(0, 0, 0)]
	vide = [(0, 0, 0) for useless in range(len(orig[0]))]
	orig.insert(0, vide) #première ligne
	orig.append(vide)    #dernière ligne
	#On crée une matrice vide contenant le résultat
	res = [[(0, 0, 0)] * len(orig[0]) for useless in range(len(orig))]
	#Pour chaque vrai pixel, on calcule avec la matrice de convolution.
	for y in range(1,len(orig)-1):
		for x in range(1,len(orig[0])-1):
			#Produit de convolution (avec les voisins)
			accu = 0
			for i in range(len(mat)):
				for j in range(len(mat[0])):
					accu += orig[y-1+i][x-1+j][0] * mat[i][j]
			#On borne le résultat entre 0 et 255
			if accu>255:
				accu = 255
			elif accu<0:
				accu = 0
			#On stocke le résultat
			res[y][x] = (accu, accu, accu)
	#On retire les bords de couleur sombre (sinon ça fait raaaciste)
	for i in range(len(res)):
		res[i] = res[i][1:-1]
	res.pop()  #dernière ligne
	res.pop(0) #première ligne
	return res
	
def is_greyscale(img):
	"""Retourne True si l'image en paramètre est déjà en nuances de gris."""
	for ligne in img:
		for pt in ligne:
			if pt[0]!=pt[1] or pt[1]!=pt[2] or pt[0]!=pt[2]:
				return False
	return True

def demanderChoix(filtres):
	"""Demande via la console le filtre à appliquer."""
	#Différentes propositions
	for i, c in enumerate(filtres):
		print ">>> Filtre ", i+1, ":", c[0]
	ch = -1
	#Tant que le choix est incorrect, on redemande
	while ch>len(filtres) or ch<1:
		ch = int(raw_input("Choix ? "))
	#On retourne un indice (directement utilisable)
	return ch-1

def circle(img, pt, radius, color):
	"""
	Dessine un cercle sur img.
	Ne donne pas très bien quand le JPEG est trop compressé...
	"""
	res = deepcopy(img)
	for angle in range(0, 361): #FIXME les points ne sont même pas joints...
		x = int(pt[0] + cos(radians(angle)) * radius)
		y = int(pt[1] + sin(radians(angle)) * radius)
		if (x in range(0, len(img[0]))) and (y in range(0, len(img))):
			res[y][x] = color
	return res

def rien(img):
	return img

filtres = [	('contours (tolérant)', [[1, 0, -1], [2, 0, -2], [1, 0, -1]]), 
			('contours (normal)', [[-1,-1,-1],[-1,8,-1],[-1,-1,-1]]), 
			('croquis', [[-1,-1,-1],[-1,9,-1],[-1,-1,-1]]), 
			('relief', [[-2,0,0],[0,1,0],[0,0,2]]),
			('négatif', invert),
			('rien', rien)]



inp = 'mikado.jpg'
out = 'output'
out_fmt = 'jpg'
out_full = out+"."+out_fmt

print "Chargement..."
img = load(inp)
img = circle(img, (500, 400), 600, (255, 0, 0))
print ">>> Hauteur", len(img), "Largeur", len(img[0])
choix = demanderChoix(filtres)
if isinstance(filtres[choix][1], list):
	print "Application du filtre..."
	if is_greyscale(img):
		print ">>> Type : nuances de gris"
		#pas besoin de convertir, donc...
	else:
		print ">>> Type : couleurs"
		print "Conversion en nuances de gris..."
		img = greyscale(img) #nécessaire pour convo !
	img = convo(img, filtres[choix][1])
else:
	if raw_input("Nuance de gris (o pour OUI) ? ").lower() == 'o':
		print "Conversion en nuances de gris..."
		img = greyscale(img)
	print "Application du filtre..."
	img = filtres[choix][1](img)
print "Enregistrement..."
save(img, out, out_fmt)
print "Terminé ! Image stockée dans", out_full
shellExecute(out_full)
